use super::Entry;
use std::path::Path;
use std::fs::{self, File};
use std::error::Error;
use std::sync::Mutex;
use zip::read::ZipArchive;
use std::io::Read;
use std::fmt;

pub struct ZipEntry {
    abs_path: String,
    zip_archive: Mutex<ZipArchive<File>>,
}

impl ZipEntry {
    pub fn new(path: &str) -> ZipEntry {
        let path = Path::new(path);
        // 转换为绝对路径
        match fs::canonicalize(path) {
            Ok(abs_path) => {
                let abs_path = abs_path.to_str().unwrap().to_string();
                let file = File::open(abs_path.as_str());
                match file {
                   Ok(file) => {
                    match ZipArchive::new(file) {
                        Ok(zip_archive) => ZipEntry { abs_path, zip_archive: Mutex::new(zip_archive) },
                        Err(e) => panic!("{}", e)
                    }
                   },
                   Err(e) => panic!("{}", e)
                }
            },
            Err(e) => panic!("{}", e)
        }
    }
}

impl Entry for ZipEntry {
    fn read_class(&self, class_name: &str) -> Result<Vec<u8>, Box<dyn Error>> {
        // 231022 每次读取ZipArchive::new太耗时，将其在创建时生成存储在结构体中。
        // 获取zip文件
        // let file = File::open(self.abs_path.as_str());
        // let mut zip = ZipArchive::new(file)?;
        let mut zip = self.zip_archive.lock().unwrap();

        // 获取指定文件, 可以获取内部文件夹中的class，如获取rt.jar中的java/lang/Object.class
        let mut file = zip.by_name(class_name)?;
        let mut data = vec![];
        file.read_to_end(&mut data)?;
        Ok(data)
    }

    fn string(&self) -> String {
        self.abs_path.clone()
    }
}

impl fmt::Display for ZipEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.string())
    }
}